﻿#!/usr/bin/env python  
import cgi,re,urllib,urllib2,base64,urlparse,Cookie,random
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.api import urlfetch

def encode_url(url):
   return base64.encodestring(url)[:-1][::-1].replace('\n','')

def decode_url(url):
   return base64.decodestring(url[::-1]).replace('\n','')

class custom_cookie(db.Model):
    id = db.StringProperty()
    domain = db.StringProperty()
    cookie = db.TextProperty()
    when =  db.DateTimeProperty(auto_now = True)

class URLOpener:
  def __init__(self,ss = ''):
      ss = ss.encode('utf8')
      self.cookie = Cookie.SimpleCookie(ss)
    
  def open(self, url, data = None,header={}):
      if data is None:
          method = urlfetch.GET
      else:
          method = urlfetch.POST
      while url is not None:
          response = urlfetch.fetch(url=url,
                  payload=data,
                  method=method,
                  headers=self._getHeaders(self.cookie,header),
                  allow_truncated=False,
                  follow_redirects=False,
                  deadline=10
                  )
          data = None 
          method = urlfetch.GET
          self.cookie.load(response.headers.get('set-cookie', ''))
          url = response.headers.get('location')
          if  url is None:
              url = response.headers.get("Location")
      return response
        
  def _getHeaders(self, cookie,header):
      header.update({'Cookie' : self._makeCookieHeader(cookie)})
      return header

  def _makeCookieHeader(self, cookie):
      cookieHeader = ""
      for value in cookie.values():
          cookieHeader += "%s=%s; " % (value.key, value.value)
      return cookieHeader

class change_html():
    def __init__(self,s,url,home):
        self.s = s
        self.url = url
        self.home = 'http://'+home
    def common_ch(self,match):
        urls = re.findall(match,self.s,re.M|re.S|re.I)
        for i,j,k in urls:
            if 'javascript:' in j.lower() or 'rtsp://' in j: 
                continue
            full = urlparse.urljoin(self.url,j)
            full = encode_url (full)
            self.s =self.s.replace(i+j+k,i+self.home+'/go_'+full+k,1)
    def ch_text(self):
        self.common_ch(r"""(<a[^>]*?href\s*=\s*['"]?)([^'"\s>]{1,500})(['">\s])""")
    def ch_js(self):
        self.common_ch(r"""(<script[^>]*?src\s*=\s*['"]?)([^'"\s>]+)(['">\s])""")
    def ch_css(self):
        self.common_ch(r"""(<link[^>]*?href\s*=\s*['"]?)([^'"\s>]+)(['">\s])""")
    def ch_img(self):
        self.common_ch(r"""(<img[^>]*?src\s*=\s*['"]?)([^'"\s>]+)(['">\s])""")
    def ch_form(self):
        self.common_ch(r"""(<form[^>]+?action\s*=\s*["']?)([^\s'">]+?)([\s'">])""")
    def ch_base(self):
        com = re.compile(r"""<!?-?-?base[^>]+?href=[^>]+?>""")
        self.s = com.sub('',self.s)
    def ch_reflash(self):
        self.common_ch(r"""(<meta[^>]*?http-equiv=["']?refresh[^>]+?url=["']?)([^>'"]+)(["'>])""")
    def ch_iframe(self):
        self.common_ch(r"""(<iframe[^>]+?src=\s*['"]?)([^'">\s]+)(['"\s>])""")
    def ch_import(self):
        self.common_ch(r"""(@import[^>\(\)]+?["'\s\(]+)([^'">\s\)\(]+)([\)'"\s>])""")

    def handle(self):
        self.ch_text()
        self.ch_js()
        self.ch_css()
        self.ch_img()
        self.ch_import()
        self.ch_form()
        self.ch_base()
        self.ch_reflash()
        self.ch_iframe()
        return self.s  

class make_url():
    def __init__(self,cur,last = None):
        self.url = urllib.unquote(cur)
        self.last = last

    def res_url(self):   
        try:
            self.url = self.url.encode('utf8')
        except:
            try:
                self.url = self.url.decode('gb18030').encode('utf8')
            except:
                pass

    def single_url(self):
        url = self.url.split("_",1)[1]
        if '?' in url:
            full = decode_url(url.split("?",1)[0])+'?'+url.split("?",1)[1]
        elif '&' in url:
            full = decode_url(url.split("&",1)[0])+'&'+url.split("&",1)[1]
        else:
            full = decode_url(url)
        full = full.replace('&amp;','&')
        full = full.replace(' ','+')
        self.url = full

    def handle(self):
     #   self.res_url()
        self.url = '/'+'/'.join(self.url.split('/')[3:])
        if self.url.startswith("/go_"):
            self.single_url()
        elif self.url.startswith("/other_"):
            self.single_url()
        elif self.last:
            self.url = urlparse.urljoin(self.single_url(last),url)
            self.single_url(self.url)
        else:
            pass
        return self.url

def create_cookie(num,home,cookie):
    tem = custom_cookie.all()
    domain = re.findall(r'domain=([^\s;]+)',cookie,re.I|re.M|re.S)
    if len(domain)>0:
        home = domain[0]
    else:
        home = '.'+'.'.join(home.split(".")[-2:])
    tem.filter("id =",num)
    tem.filter("domain =",home)
    if tem.count() == 0:
        temp = custom_cookie()
    else:
        temp = tem.order("-when").fetch(1)[0]
    temp.id = num
    temp.domain = home
    temp.cookie = cookie
    temp.put()

class index (webapp.RequestHandler):
  def get(self):
      num = self.request.cookies.get('id')
      if not num:
        num = random.randint(1000,10000)
        self.response.headers.add_header("Set-Cookie", "id="+str(num)+"; path=/")
      tem = """<form action='/' method='post'>URL:<input type='text' name='url' size=80 >
               <input type='submit' value='Go !'></form>"""
      self.response.out.write(tem)
  def post(self):
      url = self.request.get('url')
      if not url.startswith('http://'):
          url = 'http://'+url
      self.redirect('/go_'+ encode_url(url))

class go(webapp.RequestHandler):
    def common(self,url,last,headers,data,host):
        cookie = ''
        temp = make_url(url)
        url = temp.handle()
        if headers.has_key("Referer"):
            temp = make_url(last)
            last = temp.handle()
            if 'http://' in last:
                headers['Referer'] = last
            else:
                headers['Referer'] = 'http://www.google.com'
        id = self.request.cookies.get('id')
        if id:
            home = urlparse.urlparse(url)[1]
            home = '.'+'.'.join(home.split(".")[-2:])
            temp = custom_cookie.all().filter("id =",id).filter("domain =",home)
            if temp.count() != 0:
                cookie = temp.order('-when').fetch(1)[0].cookie
        req = URLOpener(cookie)
        res = req.open(url,data,headers)
        cookie1 = res.headers.get("set-cookie")
        cookie2 = res.headers.get("Set-Cookie")
        cookie = cookie1 if cookie1 else cookie2
        if cookie:
                home = urlparse.urlparse(url)[1]
                create_cookie(id,home,cookie)
        temp = change_html(res.content,url,host)
        content = temp.handle()
        content_type = res.headers['content-type']
        if content:
            self.response.headers['Content-Type'] = content_type
            if 'text' in content_type or 'www' in content_type:
                self.response.out.write("<base href='"+url+" '>") 
            self.response.out.write(content)
        else:
            self.response.out.write("srroy,something error ")
            self.response.out.write(url)

    def get(self):
        url = self.request.url
        headers = self.request.headers
        if headers.has_key('Referer'):
            last = headers.get('Referer')
        else:
            last = 'http://www.google.com'
        host = self.request.host
        data = self.request.body
        self.common(url,last,headers,None,host)

    def post(self):
        url = self.request.url
        headers = self.request.headers
        if headers.has_key('Referer'):
            last = headers.get('Referer')
        else:
            last = 'http://www.google.com'
        host = self.request.host
        data = self.request.body
        self.common(url,last,headers,data,host)

application = webapp.WSGIApplication([
  ('/', index),
  ('/.*',go)
], debug=True)

def main():
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
  main()
